﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using PGMHelper;

namespace Spectrum
{
    /// <summary>
    /// 平稳高斯参数
    /// </summary>
    public class StationaryGaussianParam
    {
        /// <summary>
        /// 功率
        /// </summary>
        private double wk { set; get; }

        /// <summary>
        /// 功率增量
        /// </summary>
        private double deltaW { set; get; }

        /// <summary>
        /// 随机相位角
        /// </summary>
        public double thetak { set; get; }

        /// <summary>
        /// 国家反应谱
        /// </summary>
        private SpectSet codeSpectrum { set; get; }

        /// <summary>
        /// 功率谱密度值
        /// 每次迭代更新谱密度
        /// </summary>
        private double Ck { set; get; }

        /// <summary>
        /// 三角级数
        /// </summary>
        private List<double> cosValues { set; get; }

        /// <summary>
        /// 误差列表
        /// </summary>
        ///private List<StationaryGaussianError> ErrorList { set; get; }

        /// <summary>
        /// 贡献系数
        /// </summary>
        public double ContributionFactor { set; get; }

        /// <summary>
        /// 误差修正系数
        /// </summary>
        public double ModifiedError { set; get; }

        /// <summary>
        /// 对应周期
        /// </summary>
        public double period
        {
            get
            {
                return Math.PI * 2 / this.wk;
            }
            set
            {

            }
        }

        #region 弃用方法

        /// <summary>
        /// 添加误差系数
        /// </summary>
        /// <param name="Ft"></param>
        /// <param name="responseMax"></param>
        /// <param name="responseMaxTime"></param>
        /// <param name="timeInterval"></param>
        /// <param name="targetPeriod"></param>
        /// <param name="Eerror"></param>
        /// <param name="R_Error"></param>
        //public void Add(EnvelopeFunction Ft, float responseMax, float responseMaxTime, double timeInterval, double targetPeriod,
        //    double Eerror, double R_Error)
        //{
        //    //计算响应
        //    var responseSub = this.GetResponseSet(Ft, timeInterval, responseMaxTime + 1, targetPeriod);
        //    //计算频率
        //    var wn = SpectrumMethod.Getwn((float)targetPeriod);
        //    //获得响应
        //    var responseSubMax = responseSub.GetResponseParam(responseMaxTime).U * Math.Pow(wn, 2);
        //    //获得符号
        //    int sign = responseSubMax * responseMax < 0 ? -1 : 1;
        //    //贡献高则添加
        //    if (Math.Abs(responseSubMax / responseMax) > ArtiWaveParam.ContributionTol)
        //    {
        //        //构造
        //        this.ErrorList.Add(new Spectrum.StationaryGaussianError
        //        {
        //            Period = targetPeriod,
        //            ContributionFactor = Math.Abs(responseSubMax / responseMax),
        //            RelativeError = Eerror,
        //            ModifiedError = Math.Pow(R_Error, sign),
        //        });
        //    }

        //}

        /// <summary>
        /// 修正功率谱密度值
        /// </summary>
        //public void ModifyPowerSpectrum()
        //{
        //    //列表为零返回
        //    if (this.ErrorList.Count == 0) return;
        //    //如果列表中的值大于1
        //    if (this.ErrorList.Count > 1)
        //    {
        //        int i = 1;
        //    }
        //    //获得贡献列表
        //    var valueList = this.ErrorList.GetPropertyList("ContributionFactor").ConvertAll(d => (double)d);
        //    //获得最大贡献对应值
        //    var maxContributeObj = this.ErrorList[valueList.IndexOf(valueList.Max())];
        //    //求解放大倍数
        //    var FactrA = new double(); var FactorB = new double();
        //    //求值
        //    this.ErrorList.ForEach(error =>
        //    {
        //        FactrA = error.ContributionFactor * error.ModifiedError;
        //        FactorB = error.ContributionFactor;
        //    });
        //    //求得调整系数
        //    var modifier = FactrA / FactorB;
        //    //根据最大贡献调整
        //    this.ModifyPowerSpectrum((float)modifier);
        //    //清空
        //    this.ErrorList.Clear();
        //}

        /// <summary>
        /// 修正功率谱密度值
        /// </summary>
        /// <param name="factor"></param>
        //public void ModifyPowerSpectrum(SortedDictionary<double, Tuple<double, double>> powerModifyDict, double tol)
        //{
        //    //获得周期列表
        //    var periodList = powerModifyDict.Keys.ToList();
        //    var modifyList = powerModifyDict.Values.ToList();
        //    //序号初始化
        //    int startIndex = periodList.Count - 2;
        //    int endIndex = periodList.Count - 1;
        //    //遍历字典
        //    for (int index = 0; index < periodList.Count; index++)
        //    {
        //        if (periodList[index] >= this.period)
        //        {
        //            if (index == 0)
        //            {
        //                startIndex = 0; endIndex = 1;
        //            }
        //            else
        //            {
        //                startIndex = index - 1; endIndex = index;
        //            }
        //            break;
        //        }
        //    }
        //    //获得相对误差
        //    var E_error = ((modifyList[endIndex].Item2 - modifyList[startIndex].Item2) /
        //        (periodList[endIndex] - periodList[startIndex]) * (this.period - periodList[startIndex]))
        //        + modifyList[startIndex].Item2;
        //    //获得误差函数值
        //    var R_Error = ((modifyList[endIndex].Item1 - modifyList[startIndex].Item1) /
        //        (periodList[endIndex] - periodList[startIndex]) * (this.period - periodList[startIndex]))
        //        + modifyList[startIndex].Item1;
        //    //计算修正的系数
        //    var modifyFactor = (Math.Abs(E_error) < tol) ? 1 : R_Error;
        //    //计算新的功率谱密度
        //    this.ModifyPowerSpectrum((float)modifyFactor);
        //}

        #endregion

        /// <summary>
        /// 构建本功率对应的非平稳随机过程
        /// </summary>
        /// <param name="Ft"></param>
        /// <param name="timeInterval"></param>
        /// <param name="duration"></param>
        /// <returns></returns>
        private List<AccelParam> GetAccelSet(EnvelopeFunction Ft, double timeInterval, double duration)
        {
            //初始化激励
            var accelList = new List<AccelParam> { new AccelParam { Accel = 0, Time = 0 } };
            //获得值
            int indexMax = Math.Min((int)(duration / timeInterval), this.cosValues.Count);
            //遍历
            for (int index = 1; index <= indexMax; index++)
            {
                //获得时间
                var time = index * timeInterval;
                //转为非平稳随机过程
                accelList.Add(new AccelParam
                {
                    Accel = (float)(this.GetAs(index - 1) * Ft.GetFt(time)),
                    Time = (float)time
                });
            }
            //设定加速度
            return accelList;
        }

        /// <summary>
        /// 获得响应值
        /// </summary>
        /// <param name="Ft"></param>
        /// <param name="timeInterval"></param>
        /// <param name="duration"></param>
        /// <returns></returns>
        public ResponseSet GetResponseSet(EnvelopeFunction Ft, double timeInterval, double duration, double targetPeriod)
        {
            //构造加速度时程
            var accelList = this.GetAccelSet(Ft, timeInterval, duration);
            //构造响应
            var response = new ResponseSet(accelList, (float)targetPeriod,
                (float)ArtiWaveParam.DampRatio, (float)timeInterval);
            //返回响应
            return response;
        }

        /// <summary>
        /// 获得某时刻的平稳高斯过程值
        /// 性能优化
        /// </summary>
        /// <param name="timeIndex"></param>
        /// <returns></returns>
        public double GetAs(int timeIndex)
        {
            return this.Ck * this.cosValues[timeIndex];
        }

        /// <summary>
        /// 修正功率谱密度
        /// </summary>
        /// <param name="fator"></param>
        public void ModifyPowerSpectrum(float modifyFactor)
        {
            //计算新的功率谱密度
            this.Ck *= modifyFactor;
        }

        /// <summary>
        /// 计算平稳高斯过程密度
        /// </summary>
        /// <param name="duration"></param>
        private double GetPowerSpectrumVale(double duration)
        {
            //参数
            var factor1 = this.codeSpectrum.GetCodeDampRatio() / (Math.PI * this.wk);
            var factor2 = Math.Pow(this.codeSpectrum.GetAfaByPeriod(2 * Math.PI / this.wk), 2);
            var factor3 = -1 / (Math.Log(-Math.PI / (this.wk * duration) * Math.Log(ArtiWaveParam.P)));
            return factor1 * factor2 * factor3;

        }

        /// <summary>
        /// 设定三角函数值
        /// 提高效率
        /// </summary>
        /// <param name="duration"></param>
        /// <param name="timeInterval"></param>
        public void SetCosValues(int indexMax, double timeInterval)
        {
            //初始化
            this.cosValues = new List<double>();
            //遍历
            for (int index = 1; index <= indexMax; index++)
                this.cosValues.Add(Math.Cos(this.wk * index * timeInterval + this.thetak));
        }

        /// <summary>
        /// 构造函数
        /// </summary>
        public StationaryGaussianParam(double wk_, double deltaW_, double thetak_, double duration, SpectSet codeSpectrum_, int factor = 4)
        {
            //获得值
            this.wk = wk_;
            this.deltaW = deltaW_;
            this.thetak = thetak_;
            //获得反应谱
            this.codeSpectrum = codeSpectrum_;
            //初始化
            this.Ck = Math.Pow(factor * this.GetPowerSpectrumVale(duration) * this.deltaW, 0.5);
        }
    }

    #region 弃用类StationaryGaussianError

    /// <summary>
    /// 平稳高斯参数对应的误差函数等值
    /// </summary>
    //public class StationaryGaussianError
    //{
    //    /// <summary>
    //    /// 周期值
    //    /// </summary>
    //    public double Period { set; get; }

    //    /// <summary>
    //    /// 贡献系数
    //    /// </summary>
    //    public double ContributionFactor { set; get; }

    //    /// <summary>
    //    /// 相对误差
    //    /// </summary>
    //    public double RelativeError { set; get; }

    //    /// <summary>
    //    /// 误差修正系数
    //    /// </summary>
    //    public double ModifiedError { set; get; }
    //}

    #endregion
}
